#ifndef PARSER_H
#define PARSER_H

#include "inc.h"
#include "tokenizer.h"

/*
 * :::::SQL Grammer:::::
 * <SQL> => <SELECT> | <DELETE> | <INSERT> | <UPDATE>
 * <SELECT> => select <COLUMN_LIST> <FROM> <JOIN>? <WHERE>?
 * <DELETE> => delete <FROM> <JOIN>? <WHERE>?
 * <INSERT> => insert <INTO> <VALUES>
 * <UPDATE> => update <TABLE_LIST> <SET> <JOIN>? <WHERE>?
 * <FROM> => from <TABLE_LIST>
 * <WHERE> => where <CONDITION>
 * <JOIN> => join <TABLE_LIST>
 * <INTO> => into <TABLE_LIST>
 * <VALUES> => value <RECORD_LIST>
 * <SET> => set <EXPR_LIST>
 * <COLUMN_LIST> => <COLUMN_NAME> | <COLUMN_NAME>, <COLUMN_LIST> | <STAR>
 * <TABLE_LIST> => <TABLE_NAME> | <TABLE_NAME>, <TABLE_LIST>
 * <RECORD_LIST> => <RECORD> | <RECORD>, <RECORD_LIST>
 * <EXPR_LIST> => <EXPR> | <EXPR>, <EXPR_LIST>
 * <COLUMN_NAME> => <IDENTIFIER>
 * <TABLE_NAME> => <IDENTIFIER>
 * <RECORD> => (NUMBER, NUMBER, NUMBER, STRING, STRING, NUMBER) |
 *             (NUMBER, NUMBER, NUMBER, NUMBER, STRING, STRING) |
 *             (NUMBER, STRING, STRING)
 * <CONDITION> => <OR>
 * <OR> => <AND> (or <AND>)*
 * <AND> => <EXPR> (and <EXPR>)*
 * <EXPR> => <COLUMN_NAME> <OPERATOR> <VALUE>
 * <OPERATOR> => > | < | = | == | >= | <= | !=
 * <VALUE> => <STRING> | <NUMBER>
 * <IDENTIFIER> => [a-zA-Z_*][a-zA-Z0-9_]*
 * <STRING> => ".*"
 * <NUMBER> => [0-9]+
 */

#define MAX_TOKEN_LEN   30
#define MAX_VALUE_LEN   100
#define MAX_AST_NODES   10
// #define TEST_AST

typedef enum {
    AST_SQL, AST_STMT_SELECT, AST_STMT_INSERT,
    AST_STMT_UPDATE, AST_STMT_DELETE, AST_CLAUSE_SELECT,
    AST_CLAUSE_INSERT, AST_CLAUSE_UPDATE, AST_CLAUSE_DELETE,
    AST_CLAUSE_INTO, AST_CLAUSE_VALUES, AST_CLAUSE_SET,
    AST_CLAUSE_FROM, AST_CLAUSE_WHERE, AST_CLAUSE_JOIN,
    AST_COLUMN_LIST, AST_TABLE_LIST, AST_RECORD_LIST,
    AST_EXPR_LIST, AST_CONDITION, AST_STAR, AST_RECORD,
    AST_COLUMN, AST_TABLE, AST_EXPR,
    AST_OR, AST_AND, AST_OPERATOR, AST_VALUE,
    AST_UNKNOWN
} ASTNodeType;

typedef struct ASTNode {
    ASTNodeType type;
    char rule[MAX_TOKEN_LEN];
    char value[MAX_VALUE_LEN];
    struct ASTNode *children[MAX_AST_NODES];
    int child_count;
} ASTNode;

ASTNode *parseSQL(const char *sql, int *index, int *last_index);
void printAST(ASTNode *root, int level);
void destroyAST(ASTNode *root);

#ifdef TEST_AST
ASTNode *parseSelect(const char *sql, int *index, int *last_index);
ASTNode *parseFrom(const char *sql, int *index, int *last_index);
ASTNode *parseWhere(const char *sql, int *index, int *last_index);
ASTNode *parseColumnList(const char *sql, int *index, int *last_index);
ASTNode *parseTableList(const char *sql, int *index, int *last_index);
ASTNode *parseCondition(const char *sql, int *index, int *last_index);
ASTNode *parseOr(const char *sql, int *index, int *last_index);
ASTNode *parseAnd(const char *sql, int *index, int *last_index);
ASTNode *parseExpr(const char *sql, int *index, int *last_index);
#endif  /* TEST_AST */

#endif  /* PARSER_H */